﻿using System;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;

using SubSonic.Repository;
using SubSonic.DataProviders;

using Fuse8.DomainFramework.DataAccess;
using Fuse8.DomainFramework.Domain;
using Fuse8.DomainFramework.Common;
using Fuse8.DomainFramework.CacheService;

namespace Fuse8.DomainFramework.SubsonicPlus.DataAccess
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    public class SubSonicEntityDataRepository<TEntity, TKey> : IEntityDataRepository<TEntity, TKey>
        where TEntity : class, IEntityObject<TKey>,new()
        where TKey : IComparable<TKey>, IEquatable<TKey> 
    {
        #region Fields

        private IRepository _repository; 

        #endregion

        #region Constructors

        public SubSonicEntityDataRepository(string connectionString, string providerName)
        {
            Guard.ArgumentNotEmpty(connectionString, "connectionString");
            Guard.ArgumentNotEmpty(providerName, "providerName");

            IDataProvider provider = ProviderFactory.GetProvider(connectionString, providerName);
            if (provider == null)
            {
                throw new ArgumentException("Can't find database provider");
            }

            _repository = new SimpleRepository(provider, SimpleRepositoryOptions.RunMigrations);
        } 

        #endregion

        #region IEntityDataRepository<T> Members

        public void Add(TEntity entityObject)
        {
            Guard.ArgumentNotNull(entityObject, "entityObject");

            _repository.Add(entityObject);
        }

        public void Save(TEntity entityObject)
        {
            Guard.ArgumentNotNull(entityObject, "entityObject");

            _repository.Update(entityObject);
        }

        public void Remove(TEntity entityObject)
        {
            Guard.ArgumentNotNull(entityObject, "entityObject");

            Remove(entityObject.Id);   
        }

        public void Remove(TKey id)
        {
            if (!id.Equals(default(TKey)))
            {
                _repository.DeleteMany<TEntity>(p => p.Id.Equals(id));
            }
        }

        public TEntity FindOne(TKey id)
        {
            return FindOne(p => p.Id.Equals(id));
        }

        public TEntity FindOne(Expression<Func<TEntity, bool>> expression)
        {
            Guard.ArgumentNotNull(expression, "entityObject");

            return _repository.Single<TEntity>(expression); 
        }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="expression"></param>
		/// <param name="selectExpression"></param>
		/// <returns></returns>
    	public TEntity FindOne(Expression<Func<TEntity, bool>> expression, Expression<Func<TEntity, object>> selectExpression)
    	{
    		throw new NotImplementedException();
    	}

    	public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> expression)
        {
            Guard.ArgumentNotNull(expression, "entityObject");

            return _repository.Find<TEntity>(expression).AsQueryable(); 
        }

		/// <summary>
		/// 
		/// </summary>
		/// <param name="expression"></param>
		/// <param name="selectExpression"></param>
		/// <returns></returns>
    	public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> expression, Expression<Func<TEntity, object>> selectExpression)
    	{
    		throw new NotImplementedException();
    	}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
    	public IQueryable<TEntity> FindAll()
        {
            return _repository.All<TEntity>();
        }

    	public IQueryable<TEntity> FindAll(Expression<Func<TEntity, object>> selectExpression)
    	{
    		throw new NotImplementedException();
    	}

    	public TEntity FindOne(IEntityCommand<TEntity> command)
        {
            throw new NotImplementedException();
        }

        public virtual IQueryable<TEntity> Find(IEntityCommand<TEntity> command)
        {
            throw new NotImplementedException();
        }

        public virtual void Execute(IEntityCommand<TEntity> command)
        {
            throw new NotImplementedException();
        }

        public DataRepositoryCacheOptions CacheOptions
        {
            get 
            {
                return DataRepositoryCacheOptions.FullCache;
            }
        }

        #endregion
    }
}
